package ru.geyes.screw.thread.atom;

/**
 * @author alex
 *         date 28.05.2008
 *         time 14:44:00
 */
public class AtomThreadAction implements Runnable {

    private Thread thread;

    private AtomAction action;

    public AtomThreadAction(AtomAction action) {
        if (action == null) throw new IllegalArgumentException("Action argument can't be null");
        this.action = action;
    }

    public boolean isStop = false;

    public boolean isRestart = false;

    public synchronized void start() {
        if (isAlive()) throw new ActionIsAliveException();
        isStop = false;
        isRestart = false;
        thread = new Thread(this);
        thread.start();
    }

    public synchronized void restart() {
        isStop = false;
        isRestart = true;
    }

    public synchronized void stop() {
        isStop = true;
        isRestart = false;
    }

    public boolean isAlive() {
        return thread != null && thread.isAlive();
    }

    public void run() {
        action.init();
        boolean stopNow = false;
        boolean isInterrupted = false;
        boolean exitWithException = false;
        
        while (!isStop && !stopNow && !isInterrupted && !exitWithException) {
            try {
                stopNow = !action.action();
            } catch (Throwable e) {
                action.exitWithException(e);
                exitWithException = true;
            }
            
            if (Thread.currentThread().getState() == Thread.State.TERMINATED && action.isStopForIterrupt()) {
                isInterrupted = true;
            }
            
            if (isRestart) {
                action.init();
                isRestart = false;
            }
            
            Thread.yield();
        }
        
        if (!exitWithException)
            action.destroy(isInterrupted);
    }
}
